/*******************************************************************************
 * FilePath    : \Software\Examples_Ble\ble_app_peripheral_ota_code\Src\BLE\app.c
 * Version     : 1.0
 * Brief       : 
 * Author      : AndrewHu
 * Company     : Shanghai MacroGiga Electronics CO.,Ltd
 * Email       : Hubinbo@macrogiga.com
 * Date        : 2020-04-03 15:06:14
 * LastEditors : AndrewHu
 * LastEditTime: 2021-04-20 15:44:43
 * Description : 
 ******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <Includes.h>
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ATT_CHAR_PROP_RD 0x02
#define ATT_CHAR_PROP_W_NORSP 0x04
#define ATT_CHAR_PROP_W 0x08
#define ATT_CHAR_PROP_NTF 0x10
#define ATT_CHAR_PROP_IND 0x20
#define GATT_PRIMARY_SERVICE_UUID 0x2800

#define TYPE_CHAR 0x2803
#define TYPE_CFG 0x2902
#define TYPE_INFO 0x2901
#define TYPE_xRpRef 0x2907
#define TYPE_RpRef 0x2908
#define TYPE_INC 0x2802
#define UUID16_FORMAT 0xff

#define MANU_INFO "MacroGiga Bluetooth"
#define SOFTWARE_INFO (__DATE__ " "__TIME__)
#define MAX_NAME_LEN 24

#define MG_OTA "MG OTA"
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
u16 cur_notifyhandle = BleRxHandle; //Note: make sure each notify handle by invoking function: set_notifyhandle(hd);
u8 gConnectedFlag = 0;
/*first byte is len, max len is 24*/
u8 DeviceInfo[MAX_NAME_LEN + 1] = {
    10,                                //设备名称长度，最长24个字节
    'M', 'S', '1', '6', '5', '6', '-', //从Flash数据中读取设备名，如果设备名有修改，将存入flash
    'O', 'T', 'A',                     //
    0x00,                              //
};
/* Private function ----------------------------------------------------------*/
/* extern --------------------------------------------------------------------*/
/*******************************************************************************
 * Function    : getDeviceInfoData
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-04-03 17:54:39
 * Description : 
 ******************************************************************************/
u8 *getDeviceInfoData(u8 *len)
{
    *len = DeviceInfo[0];
    return (u8 *)&DeviceInfo[1];
}
/*******************************************************************************
 * Function    : updateDeviceInfoData
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-04-03 17:54:58
 * Description : 
 ******************************************************************************/
void updateDeviceInfoData(u8 *name, u8 len)
{
    if (len > MAX_NAME_LEN)
        len = MAX_NAME_LEN;
    DeviceInfo[0] = len;
    memcpy(&DeviceInfo[1], name, len);
    ble_set_name(name, len);
}
/*******************************************************************************
                 *****DataBase****
*******************************************************************************/
typedef struct ble_character16
{
    u16 type16;          //type2
    u16 handle_rec;      //handle
    u8 characterInfo[5]; //property1 - handle2 - uuid2
    u8 uuid128_idx;      //0xff means uuid16,other is idx of uuid128
} BLE_CHAR;
typedef struct ble_UUID128
{
    u8 uuid128[16]; //uuid128 string: little endian
} BLE_UUID128;
/*******************************************************************************
 * Function    : 
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-23 15:23:42
 * Description : STEP0:Character declare
 ******************************************************************************/
const BLE_CHAR AttCharList[] = {
    // ======  gatt =====  Do NOT Change!!
    {GATT_PRIMARY_SERVICE_UUID, 0x0001},                                         //服务1
    {TYPE_CHAR, 0x0002, {ATT_CHAR_PROP_RD, 0x03, 0, 0x00, 0x2a}, UUID16_FORMAT}, //name，设备名
    {GATT_PRIMARY_SERVICE_UUID, 0x0004},                                         //服务2
    //05-06 reserved
    // ======  device info =====    Do NOT Change if using the default!!!
    {GATT_PRIMARY_SERVICE_UUID, 0x0007},                                         //服务3
    {TYPE_CHAR, 0x0008, {ATT_CHAR_PROP_RD, 0x09, 0, 0x29, 0x2a}, UUID16_FORMAT}, //manufacture
    {TYPE_CHAR, 0x000a, {ATT_CHAR_PROP_RD, 0x0b, 0, 0x26, 0x2a}, UUID16_FORMAT}, //firmware version
    {TYPE_CHAR, 0x000c, {ATT_CHAR_PROP_RD, 0x0d, 0, 0x28, 0x2a}, UUID16_FORMAT}, //sw version

    // ======  User service or other services added here =====  User defined
    {GATT_PRIMARY_SERVICE_UUID, 0x000e},                                                               //服务4
    {TYPE_CHAR, 0x000f, {ATT_CHAR_PROP_NTF, BleRxHandle, 0, 0, 0}, 1 /*uuid128-idx1*/},                //RxNotify
    {TYPE_CFG, 0x0011, {ATT_CHAR_PROP_RD | ATT_CHAR_PROP_W}},                                          //cfg
    {TYPE_CHAR, 0x0012, {ATT_CHAR_PROP_W | ATT_CHAR_PROP_W_NORSP, 0x13, 0, 0, 0}, 2 /*uuid128-idx2*/}, //Tx

    // ======  User service or other services added here =====  User defined
    {GATT_PRIMARY_SERVICE_UUID, 0x0014},
    {TYPE_CHAR, 0x15, ATT_CHAR_PROP_W_NORSP | ATT_CHAR_PROP_RD, 0x16, 0, 0, 0, 6 /*uuid128-idx3*/}, //OTA
    {TYPE_INFO, 0x17, ATT_CHAR_PROP_RD},                                                            //description,"Mg OTA"
};

const BLE_UUID128 AttUuid128List[] = {
    /*for supporting the android app [nRF UART V2.0], one SHOULD using the 0x9e,0xca,0xdc.... uuid128*/

    //蓝牙串口
    {0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0, 0x93, 0xf3, 0xa3, 0xb5, 1, 0, 0x40, 0x6e}, //idx0,little endian, service uuid
    {0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0, 0x93, 0xf3, 0xa3, 0xb5, 3, 0, 0x40, 0x6e}, //idx1,little endian, RxNotify
    {0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0, 0x93, 0xf3, 0xa3, 0xb5, 2, 0, 0x40, 0x6e}, //idx2,little endian, Tx

    //OTA
    {0x10, 0x19, 0x0d, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, //idx0,little endian, service uuid
    {0x11, 0x19, 0x0d, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, //idx1,little endian, character status uuid
    {0x12, 0x19, 0x0d, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, //idx2,little endian, character cmd uuid
    {0x13, 0x19, 0x0d, 0xc, 0xb, 0xa, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, //idx3,little endian, character OTA uuid
};
u8 GetCharListDim(void)
{
    return sizeof(AttCharList) / sizeof(AttCharList[0]);
}
/*******************************************************************************
 * Function    : att_server_rdByGrType
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-23 15:24:25
 * Description : STEP1:Service declare
 *               read by type request handle, primary service declare implementation
 *               蓝牙握手，获取服务句柄、句柄范围、以及服务UUID
 ******************************************************************************/
void att_server_rdByGrType(u8 pdu_type, u8 attOpcode, u16 st_hd, u16 end_hd, u16 att_type)
{
    //!!!!!!!!  hard code for gap and gatt, make sure here is 100% matched with database:[AttCharList] !!!!!!!!!

    if ((att_type == GATT_PRIMARY_SERVICE_UUID) && (st_hd == 0x0001)) //hard code for device info service
    {
        //att_server_rdByGrTypeRspDeviceInfo(pdu_type);//using the default device info service
        u8 t[] = {0x00, 0x18};
        att_server_rdByGrTypeRspPrimaryService(pdu_type, 0x01, 0x03, (u8 *)(t), 2);
        return;
    }

    if ((att_type == GATT_PRIMARY_SERVICE_UUID) && (st_hd == 0x0004)) //hard code for device info service
    {
        u8 t[] = {0x01, 0x18};
        att_server_rdByGrTypeRspPrimaryService(pdu_type, 0x04, 0x06, (u8 *)(t), 2);
        return;
    }

    else if ((att_type == GATT_PRIMARY_SERVICE_UUID) && (st_hd <= 0x0007)) //hard code for device info service
    {
        //apply user defined (device info)service example
        u8 t[] = {0x0a, 0x18};
        att_server_rdByGrTypeRspPrimaryService(pdu_type, 0x07, 0x0d, (u8 *)(t), 2);
        return;
    }

    else if ((att_type == GATT_PRIMARY_SERVICE_UUID) && (st_hd <= 0x000e)) //usr's service
    {
        // u8 t[] = {0x1c, 0x18};
        // att_server_rdByGrTypeRspPrimaryService(pdu_type, 0x0e, 0x11, (u8 *)(t), 2);
        att_server_rdByGrTypeRspPrimaryService(pdu_type, 0x0e, 0x13, (u8 *)(AttUuid128List[0].uuid128), 16);
        return;
    }

    else if ((att_type == GATT_PRIMARY_SERVICE_UUID) && (st_hd <= 0x0014)) //usr's service
    {
        // u8 t[] = {0x1c, 0x18};
        // att_server_rdByGrTypeRspPrimaryService(pdu_type, 0x0e, 0x11, (u8 *)(t), 2);
        att_server_rdByGrTypeRspPrimaryService(pdu_type, 0x14, 0x17, (u8 *)(AttUuid128List[3].uuid128), 16);
        return;
    }
    //other service added here if any
    //to do....

    ///error handle
    att_notFd(pdu_type, attOpcode, st_hd);
}
/*******************************************************************************
 * Function    : ser_write_rsp
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-23 15:49:53
 * Description : STEP2:data coming，主机(手机)执行写数据命令
 * 凡是有ATT_CHAR_PROP_W或ATT_CHAR_PROP_W_NORSP属性的特征值都要根据对饮的句柄(att_hd)来操作
 ******************************************************************************/
void ser_write_rsp(u8 pdu_type /*reserved*/, u8 attOpcode /*reserved*/,
                   u16 att_hd, u8 *attValue /*app data pointer*/, u8 valueLen_w /*app data size*/)
{
    u8 result = 0;
    switch (att_hd)
    {
    case 0x16:                                   //OTA
        result = OTA_Proc(attValue, valueLen_w); //rsp followed
        ///ser_write_rsp_pkt(pdu_type);  //ATT_CHAR_PROP_W_NORSP
        break;
    case 0x13: //BLE透传，主机（手机）写入数据
        //串口打印数据,如果发过来的数据一次超过20个字节将在ser_prepare_write函数内接收
        Uart_Send_String(attValue, valueLen_w);
        ser_write_rsp_pkt(pdu_type);
        break;
    case 0x11:
        ser_write_rsp_pkt(pdu_type);
        break;
    default:
        att_notFd(pdu_type, attOpcode, att_hd); /*the default response, also for the purpose of error robust */
        break;
    }
}

///STEP2.1:Queued Writes data if any
void ser_prepare_write(u16 handle, u8 *attValue, u16 attValueLen, u16 att_offset) //user's call back api
{
    //queued data:offset + data(size)
    //when ser_execute_write() is invoked, means end of queue write.

    //to do
    if (handle == 0x13)
    {
        Uart_Send_String(attValue, attValueLen);
    }
}

void ser_execute_write(void) //user's call back api
{
    //end of queued writes

    //to do...
}
/*******************************************************************************
 * Function    : server_rd_rsp
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-23 16:07:58
 * Description : STEP3:Read data，read response
 * 主机（手机）读取数据时，蓝牙的反馈包（返回给手机读取内容）
 ******************************************************************************/
void server_rd_rsp(u8 attOpcode, u16 attHandle, u8 pdu_type)
{
    u8 d_len;
    u8 *ble_name = getDeviceInfoData(&d_len);

    switch (attHandle) //hard code
    {
    case 0x03: //GAP name
        att_server_rd(pdu_type, attOpcode, attHandle, ble_name, d_len);
        break;

    case 0x09: //MANU_INFO
        att_server_rd(pdu_type, attOpcode, attHandle, (u8 *)(MANU_INFO), sizeof(MANU_INFO) - 1);
        // att_server_rd(pdu_type, attOpcode, attHandle, get_ble_version(), strlen((const char *)get_ble_version())); //ble lib build version
        break;

    case 0x0b: //FIRMWARE_INFO
    {
        //do NOT modify this code!!!
        att_server_rd(pdu_type, attOpcode, attHandle, GetFirmwareInfo(), strlen((const char *)GetFirmwareInfo()));
        break;
    }

    case 0x0d: //SOFTWARE_INFO
        att_server_rd(pdu_type, attOpcode, attHandle, (u8 *)(SOFTWARE_INFO), sizeof(SOFTWARE_INFO) - 1);
        break;

    case 0x11: //cfg
    {
        u8 t[2] = {0, 0};
        att_server_rd(pdu_type, attOpcode, attHandle, t, 2);
        break;
    }

    case 0x13:
    {
        att_server_rd(pdu_type, attOpcode, attHandle, (u8 *)(MG_OTA), sizeof(MG_OTA) - 1);
        break;
    }
    default:
        att_notFd(pdu_type, attOpcode, attHandle); /*the default response, also for the purpose of error robust */
        break;
    }
}

void server_blob_rd_rsp(u8 attOpcode, u16 attHandle, u8 dataHdrP, u16 offset)
{
}

//return 1 means found
int GetPrimaryServiceHandle(unsigned short hd_start, unsigned short hd_end,
                            unsigned short uuid16,
                            unsigned short *hd_start_r, unsigned short *hd_end_r)
{
    // example
    // if ((uuid16 == 0xca9e) && (hd_start <= 0x10)) // MUST keep match with the information save in function  att_server_rdByGrType(...)
    // {
    //     *hd_start_r = 0x10;
    //     *hd_end_r = 0x19;
    //     return 1;
    // }

    return 0;
}

/*******************************************************************************
 * Function    : 
 * Brief       : 
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-03-23 16:15:32
 * Description : 
 * 本回调函数可用于蓝牙模块端主动发送数据之用，协议栈会在系统允许的时候（异步）回调本函数，不得阻塞！！
 * 补充：蓝牙基本每次和手机交互时都会从这里回调，所以要在该函数内判断，有数据需要发送时才写入数据
 ******************************************************************************/
void gatt_user_send_notify_data_callback(void)
{
    //to do if any ...
    //add user sending data notify operation ....
    NotifyRun();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//u8* getsoftwareversion(void)
//{
//    return (u8*)SOFTWARE_INFO;
//}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*******************************************************************************
 * Function    : GetConnectedStatus
 * Brief       : 获取连接状态
 * Parameter   : 
 * Returns     : 
 * Date        : 2020-04-06 01:44:20
 * Description : 
 ******************************************************************************/
char GetConnectedStatus(void)
{
    return gConnectedFlag;
}

void ConnectStausUpdate(unsigned char IsConnectedFlag) //porting api
{
    //[IsConnectedFlag] indicates the connection status

    if (IsConnectedFlag)
        IsConnectedFlag = 0x01;

    if (IsConnectedFlag != gConnectedFlag)
    {
        gConnectedFlag = IsConnectedFlag;
        Printf_ConnectStatus(gConnectedFlag); //打印连接信息
    }
}
/*******************************************************************************
* Function   :      UsrProcCallback
* Parameter  :      void
* Returns    :      void
* Description:
* Note:      :      回调函数
*******************************************************************************/
void UsrProcCallback(void) //porting api
{
    WDG_ReloadCounter(); //清狗

    if (!GetConnectedStatus())
        LED_ChangeStatus();
    else
        setLedPinStatus(1);
}
/*******************************************************************************
* Function   :      UsrProcCallback
* Parameter  :      void
* Returns    :      void
* Description:
* Note:      :      回调函数
*******************************************************************************/
void UsrProcCallback_Central(u8 fin, u8 *dat_rcv, u8 dat_len)
{
}
void gatt_client_send_callback(void)
{
}
void att_cli_receive_callback(u16 att_hd, u8 *attValue /*app data pointer*/, u8 valueLen_w /*app data size*/)
{
}
